/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso;

import ohos.agp.components.Image;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorMatrix;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.miscservices.timeutility.Time;

import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY;

public class PicassoDrawable extends PixelMapElement implements Element.OnChangeListener {
    private final boolean debugging;
    private final float density;
    private final Picasso.LoadedFrom loadedFrom;
    private Element placeholder;

    // Only accessed from main thread.
    private static final Paint DEBUG_PAINT = new Paint();

    private static final float FADE_DURATION = 200f; //ms

    /**
     * Create or update the drawable on the target  to display the supplied bitmap
     * image.
     *
     * @param target     the target value
     * @param context    the context value
     * @param bitmap     the bitmap
     * @param loadedFrom the loaded from
     * @param noFade     the no fade
     * @param debugging  the debugging
     * @param data       the data
     */
    static void setBitmap(Image target, Context context, PixelMap bitmap,
                          Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging, Request data) {
        Element placeholder = target.getImageElement();
        PicassoDrawable drawable =
                new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
        target.setImageElement(drawable);

        if(data.rotationDegrees != 0.0){
             target.setRotation(data.rotationDegrees);
        }
    }

    /**
     * The Start time millis.
     */
    long startTimeMillis;
    /**
     * The Animating.
     */
    boolean animating;
    /**
     * The Alpha.
     */
    int alpha = 0xFF;

    /**
     * Instantiates a new Picasso drawable.
     *
     * @param context     the context value
     * @param bitmap      the bitmap value
     * @param placeholder the placeholder
     * @param loadedFrom  the loaded from
     * @param noFade      the no fade
     * @param debugging   the debugging
     */
    PicassoDrawable(Context context, PixelMap bitmap, Element placeholder,
                    Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
        super(bitmap);
        this.debugging = debugging;
        this.density = DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes().densityPixels;

        this.loadedFrom = loadedFrom;

        boolean fade = loadedFrom != MEMORY && !noFade;
        if (fade) {
            this.placeholder = placeholder;
            animating = true;
            startTimeMillis = Time.getRealActiveTime();
        }
    }

    /**
     * Sets placeholder.
     *
     * @param target              the target value
     * @param placeholderDrawable the placeholder drawable
     */
    static void setPlaceholder(Image target, Element placeholderDrawable) {
        target.setImageElement(placeholderDrawable);
    }

    /**
     * Sets placeholder.
     *
     * @param target         the target value
     * @param placeholderRes the placeholder res
     */
    static void setPlaceholder(Image target, int placeholderRes) {
        target.setPixelMap(placeholderRes);
    }

    private static Path getTrianglePath(int x1, int y1, int width) {
        final Path path = new Path();
        path.moveTo(x1, y1);
        path.lineTo(x1 + width, y1);
        path.lineTo(x1, y1 + width);

        return path;
    }

    @Override
    public void drawToCanvas(Canvas canvas) {
        if (!animating) {
            super.drawToCanvas(canvas);
        } else {
            float normalized = (Time.getRealActiveTime() - startTimeMillis) / FADE_DURATION;
            if (normalized >= 1f) {
                animating = false;
                placeholder = null;
                super.drawToCanvas(canvas);
            } else {
                if (placeholder != null) {
                    placeholder.drawToCanvas(canvas);
                }

                // setAlpha will call invalidateSelf and drive the animation.
                int partialAlpha = (int) (alpha * normalized);
                super.setAlpha(partialAlpha);
                super.drawToCanvas(canvas);
                super.setAlpha(alpha);
            }
        }

        if (debugging) {
            drawDebugIndicator(canvas);
        }
    }

    @Override
    public void setAlpha(int alpha) {
        this.alpha = alpha;
        if (placeholder != null) {
            placeholder.setAlpha(alpha);
        }
        super.setAlpha(alpha);
    }

    @Override
    public void setColorMatrix(ColorMatrix cf) {
        if (placeholder != null) {
            placeholder.setColorMatrix(cf);
        }
        super.setColorMatrix(cf);
    }

    @Override
    public void onChange(Element element) {
        if (placeholder != null) {
            placeholder.setBounds(getBounds());
        }
    }

    private void drawDebugIndicator(Canvas canvas) {
        DEBUG_PAINT.setColor(Color.WHITE);
        Path path = getTrianglePath(0, 0, (int) (16 * density));
        canvas.drawPath(path, DEBUG_PAINT);

        DEBUG_PAINT.setColor(new Color(loadedFrom.debugColor));
        path = getTrianglePath(0, 0, (int) (15 * density));
        canvas.drawPath(path, DEBUG_PAINT);
    }
}

